/*
 * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package java.io;

/**
 * ByteArrayInputStream包含一个内部缓冲区，其中包含可以从流中读取的字节。
 * 一个内部的计数器将跟踪read方法提供的下一个字节。
 * <p>
 * 关闭ByteArrayInputStream没有任何效果。
 * 该类中的方法可以在流被关闭后调用，并且无需生成IOException。
 *
 * @author  Arthur van Hoff
 * @see     java.io.StringBufferInputStream
 * @since   JDK1.0
 */
public
class ByteArrayInputStream extends InputStream {

    /**
     * 流的创建者提供的字节数组。
     * 元素buf[0]到buf[count-1]是唯一可以从流中读取的字节;
     * 元素buf[pos]是下一个要读取的字节。
     */
    protected byte buf[];

    /**
     * 要从输入流缓冲区中读取的下一个字符的索引。
     * 这个值应该总是非负的，并且不大于count的值。
     * 下一个要从输入流缓冲区读取的字节是buf[pos]。
     */
    protected int pos;

    /**
     * 流中当前标记的位置。
     * ByteArrayInputStream对象在构造时默认被标记在位置0。
     * 可以用mark()方法在缓冲区的另一个位置标记它们。
     * reset()方法设置当前缓冲区位置到这个点。
     * <p>
     * 如果没有设置标记，则标记的值是传递给构造函数的offset
     * (如果没有提供offset，则为0)。
     *
     * @since   JDK1.1
     */
    protected int mark = 0;

    /**
     * 比这个输入流的缓冲区中最后一个有效字符大一个的索引。
     * 这个值应该总是非负的，并且不大于buf的长度。
     * 它比buf中可以从输入流缓冲区中读取的最后一个字节的位置大1。
     */
    protected int count;

    /**
     * 创建ByteArrayInputStream，以便它使用buf作为它的缓冲区数组。
     * 缓冲区数组未被复制。
     * pos的初始值为0，,count的初始值是buf的长度。
     *
     * @param   buf   the input buffer.
     */
    public ByteArrayInputStream(byte buf[]) {
        this.buf = buf;
        this.pos = 0;
        this.count = buf.length;
    }

    /**
     * 创建ByteArrayInputStream，以便它使用buf作为它的缓冲区数组。
     * pos的初始值为offset，count的初始值是offset+length和buf.length的最小值。
     * 缓冲区数组未被复制。缓冲区的标记被设置为指定的offset。
     *
     * @param   buf      the input buffer.
     * @param   offset   the offset in the buffer of the first byte to read.
     * @param   length   the maximum number of bytes to read from the buffer.
     */
    public ByteArrayInputStream(byte buf[], int offset, int length) {
        this.buf = buf;
        this.pos = offset;
        this.count = Math.min(offset + length, buf.length);
        this.mark = offset;
    }

    /**
     * 从这个输入流中读取下一个字节的数据。
     * 字节值作为0到255之间的int类型返回。
     * 如果因为已经到达流的末尾而没有可用的字节，则返回值-1。
     * 这个读方法不能阻塞。
     *
     * @return  the next byte of data, or <code>-1</code> if the end of the
     *          stream has been reached.
     */
    public synchronized int read() {
    	// pos>=count时，返回-1
    	// 否则返回buf[pos] & 0xff
    	// buf[pos]是一个byte，对应8bit
    	// 0xff对应1111 1111
    	// 与运算后返回后8位，从byte变成int
    	// 最后pos++
        return (pos < count) ? (buf[pos++] & 0xff) : -1;
    }

    /**
     * 从这个输入流中读取最多len字节的数据到一个字节数组中。
     * 如果pos等于count，则返回-1来表示文件的末尾。
     * 否则，读取的字节数k等于len和count-pos中较小的一个。
     * 
     * 如果k为正，则按照System.arraycopy执行的方式，
     * buf[pos]到buf[pos+k-1]的字节复制到b[off]到b[off+k-1]中。
     * pos被加上k，并且 k被返回。
     * <p>
     * 这个读方法不能阻塞。
     *
     * @param   b     the buffer into which the data is read.
     * @param   off   the start offset in the destination array <code>b</code>
     * @param   len   the maximum number of bytes read.
     * @return  the total number of bytes read into the buffer, or
     *          <code>-1</code> if there is no more data because the end of
     *          the stream has been reached.
     * @exception  NullPointerException If <code>b</code> is <code>null</code>.
     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
     * <code>len</code> is negative, or <code>len</code> is greater than
     * <code>b.length - off</code>
     */
    public synchronized int read(byte b[], int off, int len) {
        if (b == null) {
            throw new NullPointerException();
        } else if (off < 0 || len < 0 || len > b.length - off) {
            throw new IndexOutOfBoundsException();
        }

        if (pos >= count) {
            return -1;
        }

        int avail = count - pos;
        if (len > avail) {
            len = avail;
        }
        // len = min(len,count-pos)
        if (len <= 0) {
            return 0;
        }
        System.arraycopy(buf, pos, b, off, len);
        pos += len;
        return len;
    }

    /**
     * 跳过这个输入流中的n个字节的输入。
     * 如果到达了输入流的末尾，则跳过的字节可能会更少。
     * 要跳过的实际字节数k等于较小的n，或者count-pos。
     * 将值k添加到pos中并返回k。
     *
     * @param   n   the number of bytes to be skipped.
     * @return  the actual number of bytes skipped.
     */
    public synchronized long skip(long n) {
        long k = count - pos;
        if (n < k) {
            k = n < 0 ? 0 : n;
        }
        // 对pos值操作即可
        pos += k;
        return k;
    }

    /**
     * 返回可从此输入流读取(或跳过)的剩余字节数。
     * 
     * 返回的值是count - pos，它是要从输入缓冲区读取的剩余字节数。
     *
     * @return  the number of remaining bytes that can be read (or skipped
     *          over) from this input stream without blocking.
     */
    public synchronized int available() {
        return count - pos;
    }

    /**
     * 测试这个输入流是否支持标记/重置。
     * ByteArrayInputStream的markSupported的方法总是返回true。
     *
     * @since   JDK1.1
     */
    public boolean markSupported() {
        return true;
    }

    /**
     * 设置流中的当前标记位置。
     * ByteArrayInputStream对象在构造时默认被标记在位置0。
     * 它们可以用这种方法标记在缓冲区的另一个位置上。
     * <p>
     * 如果没有设置标记，则标记的值是传递给构造函数的偏移量
     * (如果没有提供偏移量，则为0)。
     *
     * <p> 注意:这个类的readAheadLimit没有任何意义。
     *  
     *  
     *
     * @since   JDK1.1
     */
    public void mark(int readAheadLimit) {
        mark = pos;
    }

    /**
     * 将缓冲区重置到标记的位置。
     * 除非在构造函数中标记了其他位置或指定了偏移量，否则标记的位置为0。
     */
    public synchronized void reset() {
        pos = mark;
    }

    /**
     * 关闭ByteArrayInputStream没有任何效果。
     * 该类中的方法可以在流被关闭后调用，而无需生成IOException。
     */
    public void close() throws IOException {
    }

}
